package com.hcloud.audit.api.aspect;

import com.alibaba.fastjson.JSONObject;
import com.hcloud.audit.api.event.OperateLogEvent;
import com.hcloud.audit.api.util.IPUtils;
import com.hcloud.auth.api.util.AuthUtil;
import com.hcloud.common.core.annontion.AuthPrefix;
import com.hcloud.common.core.annontion.BaseOperateLog;
import com.hcloud.common.core.annontion.OperateLog;
import com.hcloud.common.core.annontion.OperatePostfix;
import com.hcloud.common.core.constants.OperateType;
import com.hcloud.common.core.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * @Auther hepangui
 * @Date 2018/11/20
 */
@Aspect
@Slf4j
@Component
@Order(30)
@ConditionalOnProperty(name = "hcloud.log.operate.enable",havingValue = "true")
public class OperateLogAspect {

    @Value("${hcloud.log.operate.query.enable:false}")
    private boolean enableQueryLog;


    @Around("@annotation(operateLog)")
    public Object around(ProceedingJoinPoint point, BaseOperateLog operateLog) throws Throwable {
        Object target = point.getTarget();
        OperatePostfix annotation = target.getClass().getAnnotation(OperatePostfix.class);
        if (annotation == null) {
            return point.proceed();
        } else {
            String type = operateLog.type();
            if(!enableQueryLog && OperateType.QUERY.equals(type)){
                return point.proceed();
            }
            String title = getTitle(type,annotation.value());
            long beginTime = System.currentTimeMillis();
            Object result = point.proceed();
            long time = System.currentTimeMillis() - beginTime;
            Object [] args = point.getArgs();
            saveLog(title, type,args, time);
            return result;
        }


    }


    @Around("@annotation(operateLog)")
    public Object around(ProceedingJoinPoint point, OperateLog operateLog) throws Throwable {
        String title = operateLog.title();
        String type = operateLog.type();
        if(!enableQueryLog && OperateType.QUERY.equals(type)){
            return point.proceed();
        }
        long beginTime = System.currentTimeMillis();
        Object result = point.proceed();
        long time = System.currentTimeMillis() - beginTime;
        Object [] args = point.getArgs();
        saveLog(title,type,args, time);
        return result;
    }

    private String getTitle(String type, String value) {
        switch (type){
            case OperateType.ADD : return "新增"+value;
            case OperateType.UPDATE : return "修改"+value;
            case OperateType.QUERY : return "查询"+value;
            case OperateType.DEL : return "删除"+value;
        }
        return "";
    }

    private void saveLog(String title, String type, Object [] args, long time) {
        try {
            String params = ArrayUtils.toString(args);
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String requestURI = request.getRequestURI();

            com.hcloud.audit.api.bean.OperateLog operateLogBean = com.hcloud.audit.api.bean.OperateLog.builder().params(params)
                    .type(type)
                    .uri(requestURI)
                    .ip(IPUtils.getIpAddr(request))
                    .operate(title)
                    .username(AuthUtil.getUser().getName())
                    .time(time).build();
            SpringUtil.publishEvent(new OperateLogEvent(operateLogBean));
        } catch (Exception e) {
            log.error("保存操作日志失败", e);
        }

    }
}
